using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace MetaView.Core;

/// <summary>
/// 表达式复制
/// </summary>
public class ExpressionMapper
{
    private static readonly Dictionary<string, object> m_dic = new Dictionary<string, object>();

    /// <summary>
    /// 字典缓存表达式树
    /// </summary>
    public static TOut Trans<TIn, TOut>(TIn tIn)
    {
        var key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
        if (!m_dic.ContainsKey(key))
        {
            var parameterExpression = Expression.Parameter(typeof(TIn), "p");
            var memberBindingList = new List<MemberBinding>();
            foreach (var item in typeof(TOut).GetProperties())
            {
                var property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            foreach (var item in typeof(TOut).GetFields())
            {
                var property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            var memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
            var lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, parameterExpression);
            var func = lambda.Compile();//拼装是一次性的
            m_dic[key] = func;
        }
        return ((Func<TIn, TOut>)m_dic[key]).Invoke(tIn);
    }
}